/*
 * CDynamicEngine.cpp
 *
 *  Created on: 02.03.2012
 *      Author: Kirill Blinov
 *      Copyright: LGPL
 */

#include <boost/thread.hpp>
#include <boost/unordered_map.hpp>
#include <boost/date_time.hpp>

#include "CDynamicEngine.h"
#include "Physics Engine/PhysicsEngine.h"

CDynamicEngine* CDynamicEngine::instance = NULL;

CDynamicEngine::CDynamicEngine() : loopControl(false), processingThread(NULL),
                                   messageQueue(INCOME_MESSAGE_COUNT), processingFPS(0)
{
	animationPlayer = new CSimpleAnimationPlayer();
}

CDynamicEngine::~CDynamicEngine()
{
	StopDynamicEngine();
	delete animationPlayer;
}

CDynamicEngine*
CDynamicEngine::GetEngine()
{
	if ( NULL == instance )
	{
		instance = new CDynamicEngine();
	}

	return instance;
}

void
CDynamicEngine::DeleteEngine()
{
	if ( NULL != instance )
	{
		delete instance;
		instance = NULL;
	}
}

bool
CDynamicEngine::PushMessage( IDynamicEngineMessage *Message )
{
	bool Result = ( NULL != Message );

	if ( Result )
	{
		Result = messageQueue.Send( Message );
	}

	return Result;
}

bool
CDynamicEngine::StartDynamicEngine( UINT ProcessingFPS )
{
	bool Result = false;

	if ( ProcessingFPS > 0 )
	{
		processingFPS = ProcessingFPS;
		loopControl = true;
		processingThread = new boost::thread(boost::bind(&CDynamicEngine::ProcessingThreadFunction, this));
		Result = ( processingThread != NULL );
	}

	return Result;
}

void
CDynamicEngine::StopDynamicEngine()
{
	if ( NULL != processingThread )
	{
		loopControl = false;
		processingThread->join();
		delete processingThread;
	}
}

void
CDynamicEngine::ProcessingThreadFunction()
{
	const boost::posix_time::milliseconds TargetFrameDuration = 1000 / processingFPS;
	const boost::posix_time::milliseconds FrameDurationThreashold =  TargetFrameDuration *
																	 FRAME_DURATION_THREASHOLD_PERCENT /
			                                                         100;
	boost::system_time FrameStarted = boost::get_system_time();

	while ( loopControl )
	{
		boost::system_time CurrentFrameDuration = boost::get_system_time() - FrameStarted;
		if ( CurrentFrameDuration < TargetFrameDuration - FrameDurationThreashold )
		{
			boost::system_time SleepDuration = TargetFrameDuration - CurrentFrameDuration;
			boost::this_thread::sleep( SleepDuration );
		}
		FrameStarted = boost::get_system_time();

		IDynamicEngineMessage* currentMessage;

		while( messageQueue.Receive( &currentMessage ) )
		{
			if ( NULL != currentMessage )
			{
			//TODO Add addressing with unit name
			//IUnit* CurrentUnit = currentMessage->GetSubject();
			}
		}

		//Calculate new objects animations
		/*for ( std::vector<IUnit*>::const_iterator BeginIt = GameUnitsArray.begin(),
		                          FinishIt = GameUnitsArray.end();
		                          BeginIt != FinishIt; ++BeginIt )
		{
			CurrentUnit->PlayAnimation( animationPlayer );
		}*/

		PhysicsEngine* PhysicsEngineInstance = PhysicsEngine::GetPhysicsEngine();

		//Update game world
		PhysicsEngineInstance->StepSimulate();
	}
}
